[title] Windows Workflow Foundation

--------------------------------------------------------------------------------------
[chapter] Windows Workflow Foundation (WWF)
--------------------------------------------------------------------------------------
WWF is a .Net technology added with .Net 3.0. It consists of an in-process workflow runtime
engine, a class library and a set of visual designers and tools. WWF is a framework designed for
creating and executing system or human workflows.

Here is the list of the workflow assemblies.
    * System.Workflow.Runtime.dll
    * System.Workflow.Activities.dll
    * System.Workflow.ComponentModel.dll

And here is the root workflow namespaces.
    * System.Workflow.Runtime
    * System.Workflow.Activities
    * System.Workflow.ComponentModel   
    
see also:   http://msdn.microsoft.com/workflow/
            http://codeidol.com/other/essential-windows-workflow-foundation/
            http://odetocode.com/Blogs/scott/archive/2006/08/17/5647.aspx
            http://www.softinsight.com/bnoyes/2006/08/16/UnderstandingWindowsWorkflowFoundationWFAndItsComplexities.aspx
            
--------------------------------------------------------------------------------------
Workflows and Activities
--------------------------------------------------------------------------------------
A workflow is a group of one or more elemental work items which are required in order for the 
overall work to be completed. Those work items are combined in many ways in order to form 
a flow, the workflow, and in WWF they are known as Activities.

A workflow can be depicted as a diagram of steps (activities).

WWF uses two types of workflows:
    * Sequential, which executes its activities sequentially one after the other, and
    * State Machine, which executes its activities based on a "state".

The SequentialWorkflowActivity class represents a Sequential wokflow, where the 
StateMachineWorkflowActivity class represents a State Machine workflow.

--------------------------------------------------------------------------------------
Microsoft Visual Studio wizards
--------------------------------------------------------------------------------------
Microsoft Visual Studio provides project wizards to facilitate the creation of workflows.
It is possible to create workflow classes, Workflow Library applications or Workflow Console 
applications for both types of workflows.

For demonstration purposes the easiest way is to create a workflow console application.

--------------------------------------------------------------------------------------
WorkflowRuntime class and WorkflowInstance class
--------------------------------------------------------------------------------------
Workflows are actually executed by the WWF runtime engine which is an in-process engine
and requires a host application. The workflow runtime engine creates, maintains and 
executes workflows. It can host and execute multiple workflows concurrently.

The WorkflowRuntime class represents the execution environment of the WWF runtime engine.

    public class WorkflowRuntime : IServiceProvider, IDisposable
    {
        public WorkflowRuntime();
        public WorkflowRuntime(string configSectionName);
        public WorkflowRuntime(WorkflowRuntimeSection settings);

        public bool IsStarted { get; }
        public string Name { get; set; }

        public event EventHandler<ServicesExceptionNotHandledEventArgs> ServicesExceptionNotHandled;
        public event EventHandler<WorkflowRuntimeEventArgs> Started;
        public event EventHandler<WorkflowRuntimeEventArgs> Stopped;
        public event EventHandler<WorkflowEventArgs> WorkflowAborted;
        public event EventHandler<WorkflowCompletedEventArgs> WorkflowCompleted;
        public event EventHandler<WorkflowEventArgs> WorkflowCreated;
        public event EventHandler<WorkflowEventArgs> WorkflowIdled;
        public event EventHandler<WorkflowEventArgs> WorkflowLoaded;
        public event EventHandler<WorkflowEventArgs> WorkflowPersisted;
        public event EventHandler<WorkflowEventArgs> WorkflowResumed;
        public event EventHandler<WorkflowEventArgs> WorkflowStarted;
        public event EventHandler<WorkflowSuspendedEventArgs> WorkflowSuspended;
        public event EventHandler<WorkflowTerminatedEventArgs> WorkflowTerminated;
        public event EventHandler<WorkflowEventArgs> WorkflowUnloaded;

        public void AddService(object service);
        public WorkflowInstance CreateWorkflow(Type workflowType);
        public WorkflowInstance CreateWorkflow(XmlReader workflowDefinitionReader);
        public WorkflowInstance CreateWorkflow(Type workflowType, Dictionary<string, object> namedArgumentValues);
        public WorkflowInstance CreateWorkflow(Type workflowType, Dictionary<string, object> namedArgumentValues, Guid instanceId);
        public WorkflowInstance CreateWorkflow(XmlReader workflowDefinitionReader, XmlReader rulesReader, Dictionary<string, object> namedArgumentValues);
        public WorkflowInstance CreateWorkflow(XmlReader workflowDefinitionReader, XmlReader rulesReader, Dictionary<string, object> namedArgumentValues, Guid instanceId);
        public void Dispose();
        public ReadOnlyCollection<T> GetAllServices<T>();
        public ReadOnlyCollection<object> GetAllServices(Type serviceType);
        public ReadOnlyCollection<WorkflowInstance> GetLoadedWorkflows();
        public T GetService<T>();
        public object GetService(Type serviceType);
        public WorkflowInstance GetWorkflow(Guid instanceId);
        public void RemoveService(object service);
        public void StartRuntime();
        public void StopRuntime();
    }
    
    
An application hosts the WWF runtime engine in order to execute workflows by creating
an object of the WorkflowRuntime class.

    using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
        ...
    }
    


Workflows are not executed by the primary thread of the host application. Instead they are 
executed by threads created by the WWF runtime engine, and in some cases by threads a host 
application lends to the WWF runtime engine.  


A host application uses the WorkflowInstance class in order to control a workflow object
either of the SequentialWorkflowActivity or the StateMachineWorkflowActivity class. 

    public sealed class WorkflowInstance
    {
        public Guid InstanceId { get; }
        public WorkflowRuntime WorkflowRuntime { get; }

        public void Abort();
        public void ApplyWorkflowChanges(WorkflowChanges workflowChanges);
        public void EnqueueItem(IComparable queueName, object item, IPendingWork pendingWork, object workItem);
        public void EnqueueItemOnIdle(IComparable queueName, object item, IPendingWork pendingWork, object workItem);
        public override bool Equals(object obj);
        public override int GetHashCode();
        public Activity GetWorkflowDefinition();
        public DateTime GetWorkflowNextTimerExpiration();
        public ReadOnlyCollection<WorkflowQueueInfo> GetWorkflowQueueData();
        public void Load();
        public void ReloadTrackingProfiles();
        public void Resume();
        public void Start();
        public void Suspend(string error);
        public void Terminate(string error);
        public bool TryUnload();
        public void Unload();
    }

The WorkflowInstance acts as a proxy to the actual workflow object.

    using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
        WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(MyWorkflowClass));
        instance.Start();
    }   


A Workflow class, such as the MyWorkflowClass above, acts a blueprint for a workflow. What actually
is executed is the WorkflowInstance. A WorkflowInstance instance is uniquely identified by its
InstanceId property of type Guid. That unique value is used to differentiate a running instance of
a workflow from other running instances of the same workflow.

The WorkflowRuntime class provides a set of properties, methods and events for controlling
the execution environment and getting notifications about running workflows.

    using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
        AutoResetEvent waitHandle = new AutoResetEvent(false);

        /* using anonymous methods as event handlers for WorkflowRuntime events */
        workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) 
        { 
            /* unblock the current thread upon completion of the workflow */
            waitHandle.Set();                 
        };


        workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
        {
            Console.WriteLine(e.Exception.Message);
            waitHandle.Set();
        };

        
        /* create a workflow instance and start it */
        WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(Lessons.Workflows.Workflow1));
        instance.Start();


        /* block the current thread until workflow termination or completion */
        waitHandle.WaitOne();
    }    
    
    
Most of the events of the WorkflowRuntime class, such as the WorkflowCreated and the WorkflowTerminated,
pass a parameter of type WorkflowEventArgs which provides a WorkflowInstance public property.

    public class WorkflowEventArgs : EventArgs
    {
        public WorkflowInstance WorkflowInstance { get; }
    }      

--------------------------------------------------------------------------------------
Activities and the Activity class
--------------------------------------------------------------------------------------
The elemental item of a workflow is the activity. All activities inherit directly or
indirectly from the base Activity class. 

The Activity class provides a number of properties such as the Name and QualifiedName string properties
and a number of events, not all of them accessible by the Property Grid.

    public class Activity : DependencyObject
    {     
     ...
     
        public string Description { get; set; }
        public bool Enabled { get; set; }
        public ActivityExecutionResult ExecutionResult { get; }
        public ActivityExecutionStatus ExecutionStatus { get; }
        public bool IsDynamicActivity { get; }
        public string Name { get; set; }
        public CompositeActivity Parent { get; }
        public string QualifiedName { get; }

        public event EventHandler<ActivityExecutionStatusChangedEventArgs> Canceling;
        public event EventHandler<ActivityExecutionStatusChangedEventArgs> Closed;
        public event EventHandler<ActivityExecutionStatusChangedEventArgs> Compensating;
        public event EventHandler<ActivityExecutionStatusChangedEventArgs> Executing;
        public event EventHandler<ActivityExecutionStatusChangedEventArgs> Faulting;
        public event EventHandler<ActivityExecutionStatusChangedEventArgs> StatusChanged;     
     
     ...       
    }


An Activity could be a single-action activity or a composite activity. A composite activity
contains a group of activities. All composite activities inherit from the CompositeActivity 
class. 

    public class CompositeActivity : Activity
    {

        public CompositeActivity();
        public CompositeActivity(IEnumerable<Activity> children);
        public CompositeActivity(string name);


        public ActivityCollection Activities { get; }
        public ReadOnlyCollection<Activity> EnabledActivities { get; }

    ...
    
    }
    
    
The CompositeActivity class provides the Activities property, of type ActivityCollection 
class, which is the list of contained children activities. Also, the Activity.Parent property 
returns the parent CompositeActivity object of a contained child Activity object.

At design-time an activity resembles the behavior of any other visual element which can be dropped
on the surface of a visual designer. At run-time the activity executes any specified action.

A number of predefined activity classes is contained in the WWF library. It is also possible
to create custom activity classes.


--------------------------------------------------------------------------------------
CodeActivity class
--------------------------------------------------------------------------------------
The CodeActivity class is a simple activity which provides the ExecuteCode event.
    
    public event EventHandler ExecuteCode;

The ExecuteCode event executes a, so called, "code-beside" method associated with the activity, 
in a synchronous manner. 

    public sealed class CodeActivity : Activity
    {
        public static readonly DependencyProperty ExecuteCodeEvent;

        public CodeActivity();
        public CodeActivity(string name);

        public event EventHandler ExecuteCode;
    }
--------------------------------------------------------------------------------------
SequenceActivity class
--------------------------------------------------------------------------------------
The SequenceActivity is a simple CompositeActivity derived class which may have any 
number of child activities. 

The SequenceActivity executes its child activities in sequence, one after the other and is finished
when the last child activity is finished.  

    public class SequenceActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
    {
        public SequenceActivity();
        public SequenceActivity(string name);

        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext);
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext);
        protected override void OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity);
        protected virtual void OnSequenceComplete(ActivityExecutionContext executionContext);
        protected override void OnWorkflowChangesCompleted(ActivityExecutionContext executionContext);
    }

--------------------------------------------------------------------------------------
DelayActivity class
--------------------------------------------------------------------------------------
DelayActivity class provides a delay mechanism. It pauses workflow execution for a
specified interval. It provides the property

    public TimeSpan TimeoutDuration { get; set; }
    
for specifying that interval. Also the event

    public event EventHandler InitializeTimeoutDuration;
    
may be used in order to initialize the delay interval.

    public sealed class DelayActivity : Activity, IEventActivity, IActivityEventListener<QueueEventArgs>
    {
        public static readonly DependencyProperty InitializeTimeoutDurationEvent;
        public static readonly DependencyProperty TimeoutDurationProperty;

        public DelayActivity();
        public DelayActivity(string name);

        public TimeSpan TimeoutDuration { get; set; }

        public event EventHandler InitializeTimeoutDuration;

        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext);
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext);
        protected override sealed ActivityExecutionStatus HandleFault(ActivityExecutionContext executionContext, Exception exception);
        protected override void Initialize(IServiceProvider provider);
        protected override void OnClosed(IServiceProvider provider);
    }
--------------------------------------------------------------------------------------
Conditional activities
--------------------------------------------------------------------------------------
A number of activity classes provide a property which controls the execution of the
activity, based on a specified condition. Those activities actually play the role of
an execution flow control mechanism based on conditions. 

Here is the list of those classes
    * IfElseBranchActivity (only as a child of an IfElseActivity composite activity)
    * WhileActivity
    * ReplicatorActivity
    * ConditionedActivityGroup

--------------------------------------------------------------------------------------
Condition evaluation: imperative (by code) and declarative (by XAML)
--------------------------------------------------------------------------------------
The above conditional activity classes provide a Condition or UntilCondition property.
Additionally the ConditionedActivityGroup attaches a WhenCondition property to its children.
That condition property is of type ActivityCondition and can be either a CodeCondition object
or a RuleConditionReference object. They both inherit from the ActivityCondition class.

    public abstract class ActivityCondition : DependencyObject
    {
        protected ActivityCondition();

        public abstract bool Evaluate(Activity activity, IServiceProvider provider);
    }
    
 
    public class CodeCondition : ActivityCondition
    {
        public static readonly DependencyProperty ConditionEvent;

        public CodeCondition();

        public event EventHandler<ConditionalEventArgs> Condition;

        public override bool Evaluate(Activity ownerActivity, IServiceProvider provider);
    }
    

    public class RuleConditionReference : ActivityCondition
    {
        public RuleConditionReference();

        public string ConditionName { get; set; }

        public override bool Evaluate(Activity activity, IServiceProvider provider);
    }

The class type of the condition property is selectable at design-time in the Property Grid. 
Depending on the selected type the Property Grid displays a different set of choices.

The CodeCondition class represents a condition expressed by code (imperatively). It provides 
the event

    public event EventHandler<ConditionalEventArgs> Condition
    
The condition of the CodeCondition activity is considered true when the Result property of the 
ConditionalEventArgs event parameter is set to true. 

    void actNumberLess_Condition(object sender, ConditionalEventArgs e)
    {
        e.Result = N < 5;
    }
    
The sender parameter is a reference to the activity object, not to the ActivityCondition object.


The RuleConditionReference class represents a condition expressed declaratively, using a 
design-time editor dialog box and storing rules to a XAML file, the .rules file. 
So selecting RuleConditionReference as the type of the condition property forces the Property Grid 
to display a button which leads to a rule editor dialog box.

Ultimately, that condition property, of type ActivityCondition, executes its Evaluate() method in order to evaluate 
the condition. For the CodeCondition class that Evaluate() method call ends up calling the
Condition event. For the RuleConditionReference class that Evaluate() method call forces the evaluation of its 
declarative rule.

--------------------------------------------------------------------------------------
IfElseActivity class and IfElseBranchActivity class
--------------------------------------------------------------------------------------
The IfElseActivity class is a composite activity and inherits from the CompositeActivity class.
As a CompositeActivity, it provides the Activities property which is an ActivityCollection class.
Eventually the IfElseActivity is a list of activities of type IfElseBranchActivity. A list of branches.
The IfElseActivity class is not a conditional activity. It's just a container for conditional
activities.

An IfElseActivity activity may contain any number of IfElseBranchActivity branches. All those
IfElseBranchActivity branches must have their Condition property specified properly. The last branch may 
or may not have that Condition property specified.

An IfElseActivity routes execution at a branch whose Condition property evaluates to true.

An IfElseActivity evaluates its first (left) IfElseBranchActivity branch first. If that evaluation
returns true, then the execution takes that path. Else the IfElseActivity continues by evaluating the 
next IfElseBranchActivity branch and so on.   

An IfElseBranchActivity is a also composite activity and may contain any number of other child activities.

    public sealed class IfElseActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
    {
        public IfElseActivity();
        public IfElseActivity(string name);

        public IfElseBranchActivity AddBranch(ICollection<Activity> activities);
        public IfElseBranchActivity AddBranch(ICollection<Activity> activities, ActivityCondition branchCondition);
        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext);
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext);
    }

    public sealed class IfElseBranchActivity : SequenceActivity
    {
        public static readonly DependencyProperty ConditionProperty;

        public IfElseBranchActivity();
        public IfElseBranchActivity(string name);

        public ActivityCondition Condition { get; set; }
    }
--------------------------------------------------------------------------------------
WhileActivity class
--------------------------------------------------------------------------------------
The WhileActivity class inherits from CompositeActivity class and it's a composite activity.
It can contain just a single child activity, which may be a composite activity though.
 
The WhileActivity is a conditional activity. It provides a Condition property similar to the one of 
the IfElseBranchActivity class. The WhileActivity iteratively executes its child activity as long as its Condition
property, which is of type ActivityCondition, evaluates to true.  

    public sealed class WhileActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
    {
        public static readonly DependencyProperty ConditionProperty;

        public WhileActivity();
        public WhileActivity(string name);

        public ActivityCondition Condition { get; set; }
        public Activity DynamicActivity { get; }

        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext);
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext);
    }

--------------------------------------------------------------------------------------
ReplicatorActivity class
--------------------------------------------------------------------------------------
The ReplicatorActivity class inherits from CompositeActivity class and it's a composite activity.
It can contain just a single child activity, which may be a composite activity though.

    public sealed class ReplicatorActivity : CompositeActivity
    {
        public static readonly DependencyProperty ChildCompletedEvent;
        public static readonly DependencyProperty ChildInitializedEvent;
        public static readonly DependencyProperty CompletedEvent;
        public static readonly DependencyProperty ExecutionTypeProperty;
        public static readonly DependencyProperty InitialChildDataProperty;
        public static readonly DependencyProperty InitializedEvent;
        public static readonly DependencyProperty UntilConditionProperty;

        public ReplicatorActivity();
        public ReplicatorActivity(string name);

        public bool AllChildrenComplete { get; }
        public IList CurrentChildData { get; }
        public int CurrentIndex { get; }
        public ICollection<Activity> DynamicActivities { get; }
        public ExecutionType ExecutionType { get; set; }
        public IList InitialChildData { get; set; }
        public ActivityCondition UntilCondition { get; set; }

        public event EventHandler<ReplicatorChildEventArgs> ChildCompleted;
        public event EventHandler<ReplicatorChildEventArgs> ChildInitialized;
        public event EventHandler Completed;
        public event EventHandler Initialized;

        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext);
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext);
        public bool IsExecuting(int index);
        protected override void OnClosed(IServiceProvider provider);
    }

The ReplicatorActivity is a conditional activity. It provides the UntiCondition property.

The ReplicatorActivity executes its child activity a specified number of times, each time 
creating an instance (replica) of the child activity.

The property ExecutionType controls the execution mode: Sequence or Parallel. 
In Sequence mode child activity instances are executed in sequence while in Paraller mode each child
activity instance is executed in "parallel". In parallel mode all activities are executed by the
same thread though.

The DynamicActivities property returns a collection of the running instances of the child activity
at any given time.

The number of elements in the property InitialChildData, of type IList, controls the number of 
child instances and iterations. This is how the number of iterations is specified.

The Initilized event is triggered just before the ReplicatorActivity starts executing. It's a good place
to set the InitialChildData or the ExecutionType and perform any other initialization task.

The Completed event is triggered when ReplicatorActivity finishes executing.

The ChildInitialized event is triggered when a child activity instance is initialized for execution and it
is passed the corresponding element from InitialChildData IList property. The ReplicatorChildEventArgs.InstanceData
property of that event parameter contains a reference to that InitialChildData element.

The ChildCompleted event is triggered when a child activity instance finishes executing. 

The UntilCondition property is of type ActivityCondition and works just like the Condition property
of the IfElseBranchActivity and WhileActivity class. It can be either a CodeCondition object or 
a RuleConditionReference object.    

The ReplicatorActivity evaluates its UntilCondition property just before the execution of each child activity instance.
It stops execution if the UntilCondition evaluates to true. If the UntilCondition evaluates to false but no more
child activity instances are available for execution, ReplicatorActivity hangs.

In that case a workflow change is used in order to add an additional child activity to the ReplicatorActivity activity 
which will cause the UntilCondition to evaluate to true and to terminate the execution. 

--------------------------------------------------------------------------------------
ConditionedActivityGroup class
--------------------------------------------------------------------------------------
The ConditionedActivityGroup class inherits from CompositeActivity class and it's a composite activity.
It can can contain any number of child activities. Those child activities are executed in a loop.

The ConditionedActivityGroup class is a conditional activity. The UntilCondition property 
controls the continuation of the loop. 

A WhenCondition dependency property is attached to each of the child activities of a ConditionedActivityGroup
and acts as the familiar Condition property we've seen so far. The WhenCondition is optional
and if it is not defined then the child activity will execute only once, the very first time of the
loop execution.

The ConditionedActivityGroup re-evaluates its UntilCondition just befofe any child activity
execution. The ConditionedActivityGroup loop continues as long as its UntilCondition property
returns false and the WhenCondition property of at least one of the child activities returns true.

The ConditionedActivityGroup class has a somewhat bizarre design-time appearance.
In the above half of its design-time box it provides a marquee-like rectangle where child 
activities are dropped. Only a single child activity can be selected at any time. The selected 
child is displayed in the bottom half of the design-time box. There is also a button in the 
middle which controls the preview or the edit of the selected child.


    public sealed class ConditionedActivityGroup : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
    {
        public static readonly DependencyProperty UntilConditionProperty;
        public static readonly DependencyProperty WhenConditionProperty;

        public ConditionedActivityGroup();
        public ConditionedActivityGroup(string name);

        public ActivityCondition UntilCondition { get; set; }

        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext);
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext);
        public int GetChildActivityExecutedCount(Activity child);
        public Activity GetDynamicActivity(string childActivityName);
        public static object GetWhenCondition(object dependencyObject);
        protected override void OnActivityChangeAdd(ActivityExecutionContext executionContext, Activity addedActivity);
        protected override void OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity);
        protected override void OnClosed(IServiceProvider provider);
        protected override void OnWorkflowChangesCompleted(ActivityExecutionContext executionContext);
        public static void SetWhenCondition(object dependencyObject, object value);
    }

--------------------------------------------------------------------------------------
Condition rules: declarative conditions
--------------------------------------------------------------------------------------
Conditions may defined declaratively by setting the condition property to be of type
RuleConditionReference. In that case the Property Grid displays a button which leads
to a "Rule Condition Editor" dialog box.

A conditions is defined by entering a line of code, to that dialog box, which will evaluate to
true or false. This is called "rule". That dialog box is smart enough to provide even intellisense support.
In writing a rule it is possible to use any code element visible from inside the current
workflow object such as fields, properties or methods and language operators.
The declaratively defined condition is considered valid as long as it can be represented by types 
contained in the System.CodeDom namespace and returns true or false.

Condition rules defined that declarative way are stored in a .rules XAML (Extensible Application Markup 
Language) file bound to the current workflow object which then becomes an embedded resource to the 
assembly of the project. The XAML representation of those rules in that .rules file is done by using
xml element names taken from the System.CodeDom namespace, such as the CodePrimitiveExpression class.

The System.CodeDom namespace contains classes which are able to construct source code in a language neutral
way. At run-time the workflow runtime engine reads the .rules file and based on the contained XAML code, 
generates actual source code elements using CodeDom classes, compiles the generated code and it then
evaluates the rules by executing that compiled code.

--------------------------------------------------------------------------------------
PolicyActivity class, RuleSet class and Rule class
--------------------------------------------------------------------------------------
The PolicyActivity class represents a very special and interesting activity and can be thought
of as a collection of "if-then-else" statements. 


    public sealed class PolicyActivity : Activity
    {
        public static readonly DependencyProperty RuleSetReferenceProperty;

        public PolicyActivity();
        public PolicyActivity(string name);

        public RuleSetReference RuleSetReference { get; set; }

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext);
        protected override void Initialize(IServiceProvider provider);
    }

The PolicyActivity provides the property

    public RuleSetReference RuleSetReference { get; set; }
    
That RuleSetReference object references a RuleSet object, where a RuleSet is a collection of
Rule objects. That is actually a PolicyActivity represents a collection of Rule objects.

    public class RuleSet
    {
        public RuleSet();
        public RuleSet(string name);
        public RuleSet(string name, string description);

        public RuleChainingBehavior ChainingBehavior { get; set; }
        public string Description { get; set; }
        public string Name { get; set; }
        public ICollection<Rule> Rules { get; }

        public RuleSet Clone();
        public override bool Equals(object obj);
        public void Execute(RuleExecution ruleExecution);
        public override int GetHashCode();
        public bool Validate(RuleValidation validation);
    }
    

    public class Rule
    {
        public Rule();
        public Rule(string name);
        public Rule(string name, RuleCondition condition, IList<RuleAction> thenActions);
        public Rule(string name, RuleCondition condition, IList<RuleAction> thenActions, IList<RuleAction> elseActions);

        public bool Active { get; set; }
        public RuleCondition Condition { get; set; }
        public string Description { get; set; }
        public IList<RuleAction> ElseActions { get; }
        public string Name { get; set; }
        public int Priority { get; set; }
        public RuleReevaluationBehavior ReevaluationBehavior { get; set; }
        public IList<RuleAction> ThenActions { get; }

        public Rule Clone();
        public override bool Equals(object obj);
        public override int GetHashCode();
    }
 
The Rule class provides three key properties: the RuleCondition, the ThenActions collection
and the ElseActions collection. So the "Rule" name is a misnomer. It's more than a rule.

If that RuleCondition property evaluates to true then the actions contained in the ThenActions 
collection property are executed. Else if that RuleCondition property evaluates to false then 
the actions contained in the ElseActions collection property are executed.

Eventually a Rule resembles an IF-THEN-ELSE construct. IF the condition is true
THEN the "then actions" are executed, ELSE the "else actions" are executed.

At design-time RuleSets and Rules are defined by using the Property Grid. The property RuleSetReference
of the PolicyActivity object displays a button which leads to a "Rule Set Editor" dialog box where those 
rules are defined under a RuleSet name. 

The "Rule Set Editor" dialog box displays the Rules collection of a RuleSet in a list box.
Rules can be added, edited or deleted. That same dialog box provides text boxes for editing the Condition, 
the ThenActions and the ElseActions. Regarding Rule syntax the same rules apply here as for the
declarative conditions described earlier with the exception that ThenActions and ElseActions may
contain more than one line of code. Also the Halt keyword can be used whithin an action code. The Halt
command instructs the workflow runtime engine to stop further execution. 

The Rule class also provides an Active boolean property and a Priority integer property.
The Priority affects the order of evaluation and execution of a Rule. The Rules in a RuleSet object
can be thought of as collection of items ordered by the value of their Priority property.
The higher the value the higher the Priority of the Rule. Equal Priority Rules are
executed in alphabetical order based on the value of their Name property.

--------------------------------------------------------------------------------------
Rules Evaluation and Re-evaluation
--------------------------------------------------------------------------------------
The RuleSet, not directly available at design-time, provides the property ChainingBehavior
which controls the kind of re-evaluation and subsequently the re-execution of its
Rules.

A Rule A, with a certain Priority, may be re-evaluated if some other Rule B, with an equal or
lower Priority, modifies a field or property which is used by the condition of the Rule A.

At design-time that ChainingBehavior is specified at the "Chaining" combo box or the
"Rule Set Editor" dialog box. There are three possibilities:
    * Sequential, meaning no re-evaluation takes place
    * Explicit Update Only, meaning re-evaluation is invoked by explicitly calling Update(...)
    * Full Chaining, (the default) meaning full re-evaluation.
    
Here is an example

    //Rule A, Priority 0
    IF N == 5
    THEN DoSomething()
    
    // Rule B, Priority 0
    IF SomeCondition()
    THEN N = 5
    
Based on its Priority, Rule A executes first. If the initial value of the N != 5 then nothing happens, since
Rule A has not an ELSE action defined. Rule B comes next and modifies the value of N which is used in the
condition of Rule A. If this RuleSet is a Full Chaining one, then this modification forces Rule A to
re-evaluate its condition and since now N == 5 its THEN action is executed.

The property RuleReevaluationBehavior of the Rule class it also controls the re-evaluation behavior
of a Rule. It is an enumeration with to possible values: Always and Never. The "Rule Set Editor" dialog box
contains a "Reevaluation" combo box with just those two possible values, available for each Rule.

--------------------------------------------------------------------------------------
Implicit, Explicit and Attribute based re-evaluation
--------------------------------------------------------------------------------------
Implicit re-evaluation happens when the RuleSet ChainingBehavior is set to Full Chaining,
as in the last example above. The workflow runtime engine analyzes RuleConditions 
and discovers those dependencies.

Explicit re-evaluation happens when the RuleSet ChainingBehavior is set to Explicit Update Only
and a ThenAction or ElseAction uses the Update keyword.

    IF SomeCondition()
    THEN Update(N)
    
    // or Update(this.N) or Update("N") or Update("this/N")
    
The Update keyword supports wildcard characters in the passed parameter.

    THEN Update(this.Customer.*)

Attribute based re-evaluation requires the use of special Attributes which mark methods
of the current workflow class. Here is the list

    * RuleWriteAttribute, identifies a field or property that the marked method will change 
    * RuleReadAttribute, identifies a field or property that the marked method will read
    * RuleInvokeAttribute, identifies a method that the marked method will invoke

And here is an exampble

    [RuleWrite("N")]
    void Increase()
    {
        N++;
    }
    
...

    IF N < 5
    THEN Increase()
    
The use of attributes help the workflow runtime engine to determine which calls issued by
rules affect values used in conditions.    

Chaining is dangerous because it is possible to put the WWF rules engine into an infinite loop.

--------------------------------------------------------------------------------------
State Machine workflows
--------------------------------------------------------------------------------------
A state machine consists of a finite number of states, transitions between states and actions.
The state machine is always in one of its defined states. A transition is a state change. An
action is an activity which takes place at a given moment.

In WWF the StateMachineWorkflowActivity class represents a state-machine workflow.
In WWF a state-machine workflow is driven by events. The EventDrivenActivity class represents
such an event, the StateActivity class represents a state where the SetStateActivity class
represents a transition. Actions take the form of other activities contained in an 
EventDrivenActivity object. A StateActivity may optionally contain an initialization and a finalization
activity, of type StateInitializationActivity and StateFinalizationActivity respectively.

Here is the list of the classes involved, along with their base classes
    * StateMachineWorkflowActivity : StateActivity
    * StateInitializationActivity : SequenceActivity
    * StateFinalizationActivity : SequenceActivity
    * StateActivity : CompositeActivity
    * EventDrivenActivity : SequenceActivity
    * SetStateActivity : Activity

A sequential workflow is a series of forward only steps. It is not possible to go back in a passed
activity. A state-machine workflow is a group of known states and a state may lead to any backword
of forword state, perhaps based on some condition.

In WWF a state-machine workflow has always a start state and may have a final state.
Each state can contain any number of events, in the form of EventDrivenActivity objects. Those events
may execute some actions and finally they lead to a transition to another state or even the same state.
When the final state is reached the worflow is completed.

see also:   http://en.wikipedia.org/wiki/State_machine

--------------------------------------------------------------------------------------
State Machine workflows: classes and the workflow designer
-------------------------------------------------------------------------------------- 
Microsoft Visual Studio IDE facilitates the creation of workflows and workflow projects by providing 
a set of wizards. For demonstration purposes the easiest way is to create a workflow console
application of the proper type.

A state-machine workflow may contain a number of StateActivity objects representing states.
A StateActivity can contain only the following: any number of EventDrivenActivity objects, 
an optional StateInitializationActivity, an optional StateFinalizationActivity and any number 
of other StateActivity objects. If a StateActivity contains child StateActivity objects then
it can not be the target of a transition. Only its children can be transition targets.

Double-clicking on a StateActivity presents a local menu which provides a set of menu items. 
There is a menu item for marking a StateActivity as the initial or final (completed) state of the workflow
and others for creating StateInitializationActivity and StateFinalizationActivity activities for the 
selected state.

A StateActivity has to contain at least a single EventDrivenActivity object. That local menu provides
the "Add EvenDriven" menu item for that sake. Clicking the "Add EvenDriven" menu item adds an EventDrivenActivity 
to the state and, at the same time, presents a "detail view" designer of that EventDrivenActivity activity. 
That detail view provides a clickable option which returns back to the workflow designer. Double-clicking on 
an EventDrivenActivity inside a StateActivity displays the detail-view again. A StateActivity may contain 
multiple EventDrivenActivity objects.

An EventDrivenActivity can contain any number of other activities dropped to it. This is done while in 
the EventDrivenActivity detail-view and by dragging and dropping activities from the Tool Box to the 
EventDrivenActivity box.

There is a restriction regarding EventDrivenActivity child activities though. The very first activity must implement 
the IEventActivity interface. From the pre-defined activities there are just three which meet this condition:
the DelayActivity, the HandleExternalEventActivity, and the WebServiceInputActivity. The DelayActivity is the
easier choise. It can be dropped on an EventDrivenActivity with its TimeoutDuration property set to zero.

A StateActivity may contain zero or more SetStateActivity objects. A SetStateActivity activity is a transition
activity, which means it leads execution to another state. The SetStateActivity class provides the property 
TargetStateName where that "next" state is defined by its name.  

--------------------------------------------------------------------------------------
Workflow parameters
--------------------------------------------------------------------------------------
Using an overloaded version of the WorkflowRuntime.CreateWorkflow() method

    public WorkflowInstance CreateWorkflow(Type workflowType, Dictionary<string, object> namedArgumentValues);
    
it is possible to pass a Dictionary<string, object> instance containing initial values for some or all of the
public properties of the workflow being started. Each item in the passed dictionary is a
KeyValuePair<string, object> object, where the Key is a string having the name of
a public property of the workflow.

    Dictionary<string, object> Params = new Dictionary<string, object>();
    Params.Add("Param", "Hi there");    

    WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(Lessons.Workflows.Workflow1), Params);
    instance.Start();
    
In the above example, the "Param" should be the name of a public string property in the Workflow1
or an exception is thrown.

When the workflow is completed, then it is possible to access any of its public properties
from inside of an event handler for the WorkflowCompleted event of the WorkflowRuntime class.

    workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
    {
        /* accessing a public property of the workflow by name, after workflow completion */
        string S = (string)e.OutputParameters["Param"];
        Console.WriteLine(S);

        waitHandle.Set();             
    };    

--------------------------------------------------------------------------------------
Windows Workflow Foundation services
--------------------------------------------------------------------------------------
WWF services are classes the workflow runtime engine uses in order to provide additional 
functionality to the running workflows and the workflow hosts.

WWF provides a number of predefined services such as the communication service which makes it
possible for a workflow to communicate with its host application. Other predefined services
used by WWF are the persistence service, the scheduling service, the tracking service and the
transaction service. All WWF services inherit from WorkflowRuntimeService class.

Here is a list of the predefined service classes.
 
    * ExternalDataExchangeService
    * WorkflowLoaderService
    * WorkflowSchedulerService
    * WorkflowCommitWorkBatchService
    * WorkflowPersistenceService
    * ChannelManagerService
    * TrackingService

Besides those predefined services it is possible to have custom services by inheriting from
the base service classes.

Services are pluggable, that is they used in a plug-in like way by the workflow runtime.

--------------------------------------------------------------------------------------
Local Communication services
--------------------------------------------------------------------------------------
Local Communication services enable communication between a running workflow and a host
application. The ExternalDataExchangeService class is the fundamental building block of
this communication devise.

    /* 1. create an ExternalDataExchangeService object   */
    ExternalDataExchangeService ExchangeService = new ExternalDataExchangeService();

    /* 2. register the ExternalDataExchangeService object with the workflowRuntime   */
    workflowRuntime.AddService(ExchangeService);

--------------------------------------------------------------------------------------
Local Communication services: CallExternalMethodActivity
--------------------------------------------------------------------------------------
The CallExternalMethodActivity is used by a workflow in order to call an externally 
defined method. The external method is defined by an interface type marked by the
ExternalDataExchangeAttribute attribute. That interface is considered the communication contract
between the two ends, the host and the workflow, and is implemented by a custom
class which is considered as the local communication service. There can be only a 
single impementation of that interface.

    /* the interface used as a contract between workflow host and workflow runtime engine */
    [ExternalDataExchange]
    public interface IWorkflowInfo
    {
        void InformHost(string Text);
    }

    /* a class implementing the contract interface. Only one implementation is allowed */
    public class WorkflowInfo : IWorkflowInfo
    {
        public void InformHost(string Text)
        {
            Console.WriteLine(Text);
        }
    }

Then an object of the implementor class is registered with the already registered
ExternalDataExchangeService service.

    /* 3. create an instance of the a WorkflowInfo service.
       in a real-world situation we may use a parameterized constructor here 
       in order to pass some info to the WorkflowInfo instance regarding host */
    WorkflowInfo WI = new WorkflowInfo();

    /* 4. register a WorkflowInfo service with the ExternalDataExchangeService object   */
    ExchangeService.AddService(WI);
    
The CallExternalMethodActivity provides the property InterfaceType. The Property Grid
displays a button which leads to a dialog box allowing the user to select the interface
to be used as the communication contract. Another property, the MethodName is used to 
defined the name of the external method that belongs to that interface. After selecting
the method name the Property Grid displays additional "properties" for binding the 
parameters that method requires to any available property of the workflow or any other
available object.
 
The CallExternalMethodActivity provides also the event
    public event EventHandler MethodInvoking;
which is called just before the invocation of the external method.

--------------------------------------------------------------------------------------
Local Communication services: HandleExternalEventActivity 
--------------------------------------------------------------------------------------
The HandleExternalEventActivity is used by a workflow in order to respond to an event
triggered externally by the host application. The external event is defined by an interface type 
marked by the ExternalDataExchangeAttribute attribute. That interface is considered the communication 
contract between the two ends, the host and the workflow, and is implemented by a custom
class which is considered as the local communication service. There can be only a 
single impementation of that interface.

    /* the interface used as a contract between workflow host and workflow runtime engine 
       It now contains an event too */
    [ExternalDataExchange]
    public interface IWorkflowInfo
    {
        void InformHost(string Text);

        event EventHandler<WorkflowInfoArgs> InfoAvailable;
    }
    
    public class WorkflowInfo : IWorkflowInfo
    {
        public void InformHost(string Text)
        {
            Console.WriteLine("WorkflowInfo: " + Text);


            WorkflowInfoArgs Args = new WorkflowInfoArgs(WorkflowEnvironment.WorkflowInstanceId, Text);

            if (InfoAvailable != null)
                InfoAvailable(null, Args);
        }

        public event EventHandler<WorkflowInfoArgs> InfoAvailable;
    }

The event used should be of type

    public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
    
where as type argument of the TEventArgs type parameter can be used an ExternalDataEventArgs object 
or a derived type. Here is an implementation of an ExternalDataEventArgs class.

    [Serializable]
    public class WorkflowInfoArgs : ExternalDataEventArgs
    {
        private string text = "";

        public WorkflowInfoArgs(Guid instanceID, string Text)
            : base(instanceID)
        {
            text = Text;
        }

        public string Text { get { return text; } set { text = value; } }
    }

The instanceID of type Guid is a required parameter by the base constructor and is a
unique ID of a workflow instance. The workflow runtime engine uses that ID in order
to locate the right workflow instance when calling the event.


An object of that interface implementor class is registered with the already registered
ExternalDataExchangeService service.

    WorkflowInfo WI = new WorkflowInfo();
    ExchangeService.AddService(WI);
    
The HandleExternalEventActivity provides the property InterfaceType. The Property Grid
displays a button which leads to a dialog box allowing the user to select the interface
to be used as the communication contract. Another property, the EventName is used to 
defined the name of the external event that belongs to that interface. 

The HandleExternalEventActivity provides also the event
    public event EventHandler<ExternalDataEventArgs> Invoked;
which occurs when the external event is triggered.

    /* this is the event handler of the external event */
    private void handleExternalEventActivity1_Invoked(object sender, ExternalDataEventArgs e)
    {
        WorkflowInfoArgs args = e as WorkflowInfoArgs;
        Console.WriteLine("Workflow event handler: " + args.Text );
    }
    
The HandleExternalEventActivity is a blocking activity. It blocks workflow execution and
waits until the specified event is triggered.
--------------------------------------------------------------------------------------
The ListenActivity class
--------------------------------------------------------------------------------------
The ListenActivity can be used to listen for multiple external events. 

The ListenActivity is a CompositeActivity that can only contain EventDrivenActivity activities.
It must have at least two EventDrivenActivity activities. Eventually the 
ListenActivity blocks the execution of the workflow and starts waiting until one of the events it 
contains to be triggered.

The EventDrivenActivity activities are SequenceActivity descendants and can contain a list of
other activities. The only restriction is that its first child should implement the IEventActivity Interface.
It happens than the HandleExternalEventActivity implements that IEventActivity Interface.

So a ListenActivity is actually a list of HandleExternalEventActivity branches. Each branch waits for
a specific event to occur. When an event occurs the corresponding event handler is executed and all 
other branches are cancelled and stop listening for external events.

A ListenActivity can be used only with sequential workflows. Not with state machines. 
--------------------------------------------------------------------------------------
Hosting workflows in Windows.Forms applications
--------------------------------------------------------------------------------------
Workflows going to be hosted in a Windows.Forms application, are placed in a separate
workflow library. Then the host application uses a reference to that workflow library
assembly.

Also the host application should have proper references to WWF assemblies such as the
System.Workflow.Runtime.dll etc.

Passing information and data from a running workflow to Windows.Forms controls must be
done in a synchronized manner since the workflow and the host application are executed
in different threads.

A common trick is to use methods which check to see if InvokeRequired and if yes they
call themselves a second time using Invoke().

    private delegate void WorkflowDoneDelegate();

    private void WorkflowDone()
    {
        if (this.InvokeRequired)
        {
            /* if synchronization is required, then re-call itself through an invoked delegate */
            WorkflowDoneDelegate d = delegate() { WorkflowDone(); };
            this.Invoke(d);
        }
        else
        {
            btnStartWorkflow.Enabled = true;
            lboInfo.Items.Add("-----------");
        }
    }

--------------------------------------------------------------------------------------
Persistence services
--------------------------------------------------------------------------------------
A workflow instance can be unloaded from the memory and saved to a persisted storage medium.
Later on it can be loaded into memory again and continue execution. WWF Persistence services provide
this kind of functionality.

Persistence service classes inherit from the abstract WorkflowPersistenceService class and
implement its abstract methods. 


    public abstract class WorkflowPersistenceService : WorkflowRuntimeService
    {
        protected WorkflowPersistenceService();

        protected static byte[] GetDefaultSerializedForm(Activity activity);
        protected internal static bool GetIsBlocked(Activity rootActivity);
        protected internal static string GetSuspendOrTerminateInfo(Activity rootActivity);
        protected internal static WorkflowStatus GetWorkflowStatus(Activity rootActivity);
        protected internal abstract Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity);
        protected internal abstract Activity LoadWorkflowInstanceState(Guid instanceId);
        protected static Activity RestoreFromDefaultSerializedForm(byte[] activityBytes, Activity outerActivity);
        protected internal abstract void SaveCompletedContextActivity(Activity activity);
        protected internal abstract void SaveWorkflowInstanceState(Activity rootActivity, bool unlock);
        protected internal abstract bool UnloadOnIdle(Activity activity);
        protected internal abstract void UnlockWorkflowInstanceState(Activity rootActivity);
    }



A workflow can be persisted when  
    * the workflow instance is completed or terminated 
    * the workflow instance becomes idle
    * the host application calls WorkflowInstance.Unload() or WorkflowInstance.TryUnload on the workflow instance 
    * a custom activity marked with the PersistOnCloseAttribute attribute completes execution
    * atomic transactions in TransactionScopeActivity activities and CompensatableTransactionScopeActivity activities are completed.

The "persist on delay" case happens when a DelayActivity is encountered and a persistence service, with 
its UnloadOnIdle flag set to true, is already added to the workflow runtime. The workflow instance
is persisted when the DelayActivity starts waiting and is loaded back again when the TimeoutDuration
of the DelayActivity elapses.

To explicitly persist a workflow instance, the Unload(), TryUnload() and Load() methods of the
WorklflowInstance class are used. Those methods are called from the host application side.
 
The WorkflowInstance.Unload() unloads the workflow instance from the memory and persists it
using the provided persistence service. This call blocks execution on the callind thread 
if the workflow executes an activity and waits until the activity completes, before proceed. 

The WorkflowInstance.TryUnload() tries to unload and persist the workflow instance. This call
does not block though. It returns true on success, false otherwise. False is returned if the workflow
instance can not be persisted at the moment of call because it is not idle or is not suspended
or it is already completed.

The WorkflowInstance.Load() loads a previously unloaded and persisted workflow instance based
on the InstanceId of the workflow instance.

WWF provides a predefined persistence service, the SqlWorkflowPersistenceService class, which 
persists workflow instances to a MS SQL server database. Two sql scripts, found at
<%WINDIR%>\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL help in creating
the required database the SqlWorkflowPersistenceService uses to persist workflows.

A persistence service is added to the workflow runtime just like any other service.

    workflowRuntime.AddService(new SqlWorkflowPersistenceService(ConnectionString));

WWF supports binary formatting only in persisting workflow instances. The Activity class
provides the Save() and Load() methods in order to serialize a tree of activities.

    using (FileStream FS = new FileStream(FileName, FileMode.CreateNew))
    {
        IFormatter formatter = new BinaryFormatter();
        formatter.SurrogateSelector = ActivitySurrogateSelector.Default;
        activity.Save(FS, formatter);
    }
    
...

    using (FileStream FS = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        FS.Position = 0;
        IFormatter formatter = new BinaryFormatter();
        formatter.SurrogateSelector = ActivitySurrogateSelector.Default;
        return Activity.Load(FS, activity, formatter);
    }             


Serialization surrogates are classes that implement the ISerializationSurrogate interface 
and they know how to serialize objects of a some particular type. SurrogateSelector
classes are selector objects that assist formatters in selecting a proper serialization
surrogate for a certain type. The ActivitySurrogateSelector class is a surrogate selector
for Activity classes. The ActivitySurrogateSelector.Default property provides a default
internal implementation of a serialization surrogate.

Here is a simple custom persistence service class.

    /* a custom persistence service class which saves workflow instances to disk files */
    public class CustomPersistenceService : WorkflowPersistenceService
    {
        private string folder;
        private bool unloadOnIdle = false;

        /* creates a full filename for the serialization data file */
        string CreateFileName(Guid ID)
        {
            return Path.Combine(folder, ID.ToString() + ".wwf");
        }


        /* serializes and saves the activity to a disk file.     
     
            There may be situations where multiple instances of the workflow runtime engine share the
            same datastore when persisting workflows. WWF provides a locking mechanism in order to prevent
            persistence services that run in two different processes from loading the same workflow instance 
            into memory at the same time. If a custom persistence service is to support that locking mechanism 
            then the LoadWorkflowInstanceState() method must throw a WorkflowOwnershipException if the workflow
            being loaded is locked by another process. It also must lock the datastore while loading the workflow.
            The UnlockWorkflowInstanceState() method unlocks a previously locked instance. Also the SaveWorkflowInstanceState() 
            method provides the unlock boolean parameter to indicate whether state information of a workflow instance 
            being serialized should remain in an un-locked state while in the datastore. 
         */
        void Save(Activity activity, bool unlock)
        {
            Guid ID = (Guid)activity.GetValue(Activity.ActivityContextGuidProperty);

            string FileName = this.CreateFileName(ID);

            if (File.Exists(FileName))
                File.Delete(FileName);

            using (FileStream FS = new FileStream(FileName, FileMode.CreateNew))
            {
                /*  
                    Serialization surrogates are classes that implement the ISerializationSurrogate interface 
                    and they know how to serialize objects of a some particular type. SurrogateSelector
                    classes are selector objects that assist formatters in selecting a proper serialization
                    surrogate for a certain type. The ActivitySurrogateSelector class is a surrogate selector
                    for Activity classes. The ActivitySurrogateSelector.Default property provides a default
                    internal implementation of a serialization surrogate
                 */
                IFormatter formatter = new BinaryFormatter();
                formatter.SurrogateSelector = ActivitySurrogateSelector.Default;
                activity.Save(FS, formatter);
            }


            if (!unlock)
                File.SetAttributes(FileName, FileAttributes.ReadOnly);
        }


        /* locates a disk file, based on the ID, and loads the data to the activity */
        Activity Load(Guid ID, Activity activity)
        {
            string FileName = this.CreateFileName(ID);

            using (FileStream FS = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                /* see the comment for surrogates in the Save() method */
                FS.Position = 0;
                IFormatter formatter = new BinaryFormatter();
                formatter.SurrogateSelector = ActivitySurrogateSelector.Default;
                return Activity.Load(FS, activity, formatter);
            }
        }



        public CustomPersistenceService(string Folder)
        {
            this.folder = Folder;
        }

        public CustomPersistenceService(string Folder, bool unloadOnIdle)
            : this(Folder)
        {
            this.unloadOnIdle = unloadOnIdle;
        }


        protected override bool UnloadOnIdle(Activity activity)
        {
            return this.unloadOnIdle;
        }

        protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
        {
            this.Save(rootActivity, unlock);
        }

        protected override Activity LoadWorkflowInstanceState(Guid instanceId)
        {
            return Load(instanceId, null);
        }

        protected override void UnlockWorkflowInstanceState(Activity rootActivity)
        {
            Guid ID = (Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty);
            string FileName = this.CreateFileName(ID);
            using (FileStream FS = new FileStream(FileName, FileMode.Open))
            {
                File.SetAttributes(FileName, FileAttributes.Normal);
            }
        }

        protected override void SaveCompletedContextActivity(Activity activity)
        {
            this.Save(activity, true);
        }

        protected override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity)
        {
            return Load(scopeId, outerActivity);
        }

    }

    
--------------------------------------------------------------------------------------
Tracking services
--------------------------------------------------------------------------------------
In WWF Tracking services are used to capture and record information regarding workflow execution. 
The recorded information may include workflow events, activity state changes and other information.
The tracking service could write that recorded information to a log file or to a database and it
also has the possibility to filter the recorded information by using a tracking profile which is
represented by the TrackingProfile class.

The tracking service base class is the TrackingService class.

    public abstract class TrackingService : WorkflowRuntimeService
    {
        protected TrackingService();
        protected internal abstract TrackingProfile GetProfile(Guid workflowInstanceId);
        protected internal abstract TrackingProfile GetProfile(Type workflowType, Version profileVersionId);
        protected internal abstract TrackingChannel GetTrackingChannel(TrackingParameters parameters);
        protected internal abstract bool TryGetProfile(Type workflowType, out TrackingProfile profile);
        protected internal abstract bool TryReloadProfile(Type workflowType, Guid workflowInstanceId, out TrackingProfile profile);
    }

WWF provides a predefined tracking service, the SqlTrackingService class, which 
records tracking information into a MS SQL server database. Two sql scripts, found at
<%WINDIR%>\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL help in creating
the database the SqlTrackingService uses.
 
A tracking service is added to the workflow runtime just like any other service.

    workflowRuntime.AddService(new SqlTrackingService(ConnectionString));    
    
The SqlTrackingQuery class is used to query the MS SQL database and retrieve tracking information. 
The information is returned as a SqlTrackingWorkflowInstance object. The returned 
SqlTrackingWorkflowInstance object contains all the available tracking information regarding 
a specified workflow instance ID.    

    SqlTrackingQuery q = new SqlTrackingQuery(ConString); 

    SqlTrackingWorkflowInstance stwi;
    q.TryGetWorkflow(instanceId, out stwi);
    
    if (stwi != null)
    {
        lboInfo.Items.Add(string.Format("Tracking information for {0}", instanceId)); 

        lboInfo.Items.Add("Workflow events ===============================");
        foreach (WorkflowTrackingRecord wtr in stwi.WorkflowEvents)
            lboInfo.Items.Add(string.Format("({0})   Status: {1}", wtr.EventDateTime, wtr.TrackingWorkflowEvent));

        lboInfo.Items.Add("Activity events ===============================");
        foreach (ActivityTrackingRecord atr in stwi.ActivityEvents)
            lboInfo.Items.Add(string.Format("({0})   Activity: {1}   Status: {2}", atr.EventDateTime, atr.QualifiedName, atr.ExecutionStatus));
    }
    
    
     
The tracking information the workflow runtime sends to the tracking service for recording can be filtered
by using tracking profiles which are lists of track points. A tracking profile is stored into
the MS SQL database using the UpdateTrackingProfile stored procedure contained in the sql scripts used to
create the database.


    TrackingProfile profile = new TrackingProfile();
    profile.Version = new Version("1.0.0");

    /* ActivityTrackingLocation defines the activities and their events we want to track */
    ActivityTrackingLocation atl = new ActivityTrackingLocation(typeof(Activity));
    atl.MatchDerivedTypes = true;
    atl.ExecutionStatusEvents.Add(ActivityExecutionStatus.Executing);

    /* ActivityTrackPoint defines a activity related point of interest in the potential execution path of a workflow */
    ActivityTrackPoint atp = new ActivityTrackPoint();
    atp.MatchingLocations.Add(atl);
    profile.ActivityTrackPoints.Add(atp);

    /* WorkflowTrackPoint defines a workflow related point of interest in the potential execution path of a workflow */
    WorkflowTrackPoint wtp = new WorkflowTrackPoint();

    Array events = Enum.GetValues(typeof(TrackingWorkflowEvent));
    foreach (TrackingWorkflowEvent ev in events)
        wtp.MatchingLocation.Events.Add(ev);

    profile.WorkflowTrackPoints.Add(wtp);

    StringWriter SW = new StringWriter(new StringBuilder());
    TrackingProfileSerializer serializer = new TrackingProfileSerializer();
    serializer.Serialize(SW, profile);


    using (SqlConnection Con = new SqlConnection(ConString))
    {

        SqlCommand Cmd = new SqlCommand();
        Cmd.Connection = Con;
        Cmd.CommandType = CommandType.StoredProcedure;
        Cmd.CommandText = "dbo.UpdateTrackingProfile";

        Cmd.Parameters.Add(new SqlParameter("@TypeFullName", typeof(Lessons.Workflows.Workflow1).ToString()));
        Cmd.Parameters.Add(new SqlParameter("@AssemblyFullName", typeof(Lessons.Workflows.Workflow1).Assembly.FullName));
        Cmd.Parameters.Add(new SqlParameter("@Version", "1.0.0"));
        Cmd.Parameters.Add(new SqlParameter("@TrackingProfileXml", SW.ToString()));

        Con.Open();
        Cmd.ExecuteNonQuery();
    }
    

--------------------------------------------------------------------------------------
Scheduling services
--------------------------------------------------------------------------------------
In WWF Scheduling services schedule the execution of workflows in regard to threads.
There are two predefined scheduling services, the DefaultWorkflowSchedulerService and the
ManualWorkflowSchedulerService. All scheduling services derive from the base abstract
class WorkflowSchedulerService.

    public abstract class WorkflowSchedulerService : WorkflowRuntimeService
    {
        protected WorkflowSchedulerService();

        protected internal abstract void Cancel(Guid timerId);
        protected internal abstract void Schedule(WaitCallback callback, Guid workflowInstanceId);
        protected internal abstract void Schedule(WaitCallback callback, Guid workflowInstanceId, DateTime whenUtc, Guid timerId);
    }
    
By default the workflow runtime uses the DefaultWorkflowSchedulerService which schedule workflows to run on 
threads coming from the CLR's thread pool. There is a thread pool per process. Thus, by default,
workflows execute asynchronously on a background thread.

    public class DefaultWorkflowSchedulerService : WorkflowSchedulerService
    {
        public DefaultWorkflowSchedulerService();
        public DefaultWorkflowSchedulerService(int maxSimultaneousWorkflows);
        public DefaultWorkflowSchedulerService(NameValueCollection parameters);

        public int MaxSimultaneousWorkflows { get; }

        protected internal override void Cancel(Guid timerId);
        protected override void OnStarted();
        protected internal override void Schedule(WaitCallback callback, Guid workflowInstanceId);
        protected internal override void Schedule(WaitCallback callback, Guid workflowInstanceId, DateTime whenUtc, Guid timerId);
        protected internal override void Stop();
    }

The ManualWorkflowSchedulerService schedule workflows to run on a thread the host application
lends to the workflow runtime. That thread is the primary thread of the host application, so
the workflow is executed in a synchronous mode. This means that execution of the host application
is blocked until the workflow instance becomes idle or completed.

    public class ManualWorkflowSchedulerService : WorkflowSchedulerService
    {
        public ManualWorkflowSchedulerService();
        public ManualWorkflowSchedulerService(bool useActiveTimers);
        public ManualWorkflowSchedulerService(NameValueCollection parameters);

        protected internal override void Cancel(Guid timerId);
        protected override void OnStarted();
        public bool RunWorkflow(Guid workflowInstanceId);
        protected internal override void Schedule(WaitCallback callback, Guid workflowInstanceId);
        protected internal override void Schedule(WaitCallback callback, Guid workflowInstanceId, DateTime whenUtc, Guid timerId);
        protected internal override void Stop();
    }

Here is how to use the ManualWorkflowSchedulerService service.

    workflowRuntime2 = new WorkflowRuntime();

    scheduler = new ManualWorkflowSchedulerService();
    workflowRuntime2.AddService(scheduler);

    instance = workflowRuntime2.CreateWorkflow(typeof(Lessons.Workflows.Workflow1));
    instance.Start();
    scheduler.RunWorkflow(instance.InstanceId);  
    
It is also possible to create custome scheduling services by inheriting from the base WorkflowSchedulerService class.          
    
NOTE: The WWF runtime engine uses one thread per workflow instance. This is true even when
a workflow contains a ParallelActivity.
--------------------------------------------------------------------------------------
Faults: throwing and handling
--------------------------------------------------------------------------------------
The ThrowActivity class is used to throw an exception. The ThrowActivity provides the
FaultType property which gets or sets the exception type. The Property Grid displays
a button which leads to the "Browse and Select a .Net type" dialog box in order to
help the user to locate a proper Exception class.

Any unhandled exception triggers the WofkflowRuntime.WorkflowTerminated event and 
terminates abnormally the execution of the running workflow.

Exception handling inside workflows is performed by the special FaultHandlerActivity class. 
The FaultHandlerActivity class can be a child to a composite activity only.

A FaultHandlerActivity is similar to a catch clause in a try-catch block. Like the
ThrowActivity it provides a FaultType property which gets or sets the exception type
to catch.

There is also the FaultHandlersActivity class which is a composite activity which may
contain any number of FaultHandlerActivity activities and other activities.

Fault handler activities used in two places: at workflow level and at a local level,
where local level is the scope of a composite activity.

While in the workflow designer, the workflow and the composite activities provide a
local menu, accessible by left clicking the icon of the item, which contains the 
"View Fault Handlers" menu item. That menu item provides a "fault handling view"
of the selected item. That view is actualy a FaultHandlersActivity composite activity where the user 
can place FaultHandlerActivity items for handling specific fault types, and other activity types.

--------------------------------------------------------------------------------------
Cancellations: CancellationHandlerActivity
--------------------------------------------------------------------------------------
Cancellation works in the same manner as the fault handling. It is defined in global
or local level using the workflow designer.

Cancellation happens when a composite activity is canceled before all its child activities
complete execution.

CancellationHandlerActivity is the parent for child activities which contain cancellation behavior,
that is cleanup code for a cancelled composite activity or a cancelled workflow.
--------------------------------------------------------------------------------------
Transactions: TransactionScopeActivity
--------------------------------------------------------------------------------------
The TransactionScopeActivity defines a transaction scope inside a workflow. Activities
enclosed by a TransactionScopeActivity are executed inside a transaction. 

The TransactionScopeActivity activity uses internally types from the System.Transactions
namespace and it will automatically roll back any action in the case of an error.

The TransactionScopeActivity can not contain other TransactionScopeActivity items and
it requires the presence of a persistence service in order to work.

--------------------------------------------------------------------------------------
WWF dependency property system
--------------------------------------------------------------------------------------
All Activity classes inherit from the base System.Workflow.ComponentModel.DependencyObject 
class. The DependencyObject class is the base class for all classes that have dependency properties.

A dependency property is a special property defined as a static public field using
special notation. Here is an example of a proper definition of a dependency property.

    public class DependencyActivity: Activity
    {
        public static DependencyProperty TextProperty = DependencyProperty.Register("Text", 
                                                                                    typeof(string), 
                                                                                    typeof(DependencyActivity), 
                                                                                    new PropertyMetadata("<default text value>")
                                                                                    );
            
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        public string Text
        {
            get
            {
                return ((string)(base.GetValue(TextProperty)));
            }
            set
            {
                base.SetValue(TextProperty, value);
            }
        }
    }

The PropertyMetadata is an object which is used by CLR in order to get reflection-like
information regarding the property.

A DependencyObject instance keeps a hash table that stores the current values of any dependency property 
applied to it. A dependency property "backs up" a CLR property. In the above example the TextProperty
dependency property backs up the Text CLR property.

Dependency properties can be used in XAML code, that is in setting property values declaratively.
Also dependency properties can be used as attached properties, if they defined by using the
DependencyProperty.RegisterAttached() instead of the DependencyProperty.Register() method.s

Attached properties are properties of an outer object that appear to be as properties of
an inner object. In some way they extend any contained object. For example the ConditionedActivityGroup 
attaches a WhenCondition property to each contained child. Attached properties can be used in XAML.
The also used by the Property Grid. They can not be used at run-time though.

A dependency property supports a special type of binding. It can be bound to a field, property or
method of another object visible to the dependence property. The actual value of a property which is
bound to a target, is not determined until run-time. The Property Grid displays a button
which leads to a "Bind ...." dialog box for the user to select the binding target.

There are two types of activity properties: metadata properties and instance properties. 

A metadata property is immutable at run-time, thus it must be set at design-time. A metadata
property can not be bound to a target. Metadata properties exist to guarantee the integrity of an activity. 
The Name property of an Activity or the InterfaceType of a HandleExternalEventActivity  are examples 
of metadata properties.  

An instance property can be set at run-time or it can be bound to a target. 
An instance property can be either a plain CLR property or a dependency property.

Any type used in activity properties must be marked as serializable.

--------------------------------------------------------------------------------------
Custom Activities 
--------------------------------------------------------------------------------------
It is possible to create custom activity classes by inheriting from the predefined
activity classes and by adding custom execution logic, properties and events in order
to encapsulate common functionality.

A custom activity overrides the base Execute() method which returns an ActivityExecutionStatus 
enumeration value to indicate the status of the activity after the method completes.

    [ActivityValidator(typeof(InputActivityValidator))]
	public partial class InputActivity: Activity
	{
        string title = "<dialog title>";
        string text = "<dialog text>";
        string input = "";
        bool result = false;        

		public InputActivity()
		{
			InitializeComponent();
		}

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext context)
        {
            if (BeforeDialog != null)
                BeforeDialog(this, EventArgs.Empty);

            result = InputDialog.Execute(Title, Text, ref input);


            if (AfterDialog != null)
                AfterDialog(this, EventArgs.Empty); 

            /* return a status to indicate that the activity is complete */
            return ActivityExecutionStatus.Closed;
        }


        /* properties */
        [Browsable(true)]
        public string Title { get { return title; } set { title = value; } }

        [Browsable(true)]
        public string Text { get { return text; } set { text = value; } }

        [Browsable(true)]
        public string Input { get { return input; } set { input = value; } }

        [Browsable(true)]
        public bool Result { get { return result; } set { result = value; } }


        /* events */
        [Browsable(true)]
        public event EventHandler BeforeDialog;

        [Browsable(true)]
        public event EventHandler AfterDialog;
	}

An ActivityValidator derived class is used in order to validate property values of an
activity at design-time and at run-time

    /* a simple validator for InputActivity properties */
    public class InputActivityValidator : ActivityValidator
    {
        public override ValidationErrorCollection ValidateProperties(ValidationManager manager, object obj)
        {
            /* errorList is the return data and stores any errors found  */
            ValidationErrorCollection errorList = base.ValidateProperties(manager, obj);

            InputActivity a = obj as InputActivity;
            if (a != null)
            {
                if (string.IsNullOrEmpty(a.Title))
                    errorList.Add(ValidationError.GetNotSetValidationError("Title"));

                if (string.IsNullOrEmpty(a.Text))
                    errorList.Add(ValidationError.GetNotSetValidationError("Text"));

            }

            return errorList;
        }
    }


A custom activity class may or may not contain dependency properties.

	public partial class InputDependencyActivity: Activity
	{
        public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(InputDependencyActivity), new PropertyMetadata("Dialog box title"));
        public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(InputDependencyActivity), new PropertyMetadata("Dialog box text"));
        public static DependencyProperty InputProperty = DependencyProperty.Register("Input", typeof(string), typeof(InputDependencyActivity), new PropertyMetadata("Dialog box input"));
        public static DependencyProperty ResultProperty = DependencyProperty.Register("Result", typeof(bool), typeof(InputDependencyActivity));

        public static DependencyProperty BeforeDialogEvent = DependencyProperty.Register("BeforeDialog", typeof(EventHandler<EventArgs>), typeof(InputDependencyActivity), new PropertyMetadata(null));
        public static DependencyProperty AfterDialogEvent = DependencyProperty.Register("AfterDialog", typeof(EventHandler<EventArgs>), typeof(InputDependencyActivity), new PropertyMetadata(null));
        

        public InputDependencyActivity()
		{
			InitializeComponent();
		}


        protected override ActivityExecutionStatus Execute(ActivityExecutionContext context)
        {
 
            base.RaiseGenericEvent<EventArgs>(BeforeDialogEvent, this, EventArgs.Empty);

            string S = Input;
            Result = InputDialog.Execute(Title, Text, ref S);

            if (Result)
                Input = S;
 
            base.RaiseGenericEvent<EventArgs>(AfterDialogEvent, this, EventArgs.Empty);

            /* return a status to indicate that the activity is complete */
            return ActivityExecutionStatus.Closed;
        }


        /* properties */
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        public string Title
        {
            get
            {
                return ((string)(base.GetValue(TitleProperty)));
            }
            set
            {
                base.SetValue(TitleProperty, value);
            }
        }
                
        ...



        /* events */
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        public event EventHandler<EventArgs> BeforeDialog
        {
            add
            {
                base.AddHandler(BeforeDialogEvent, value);
            }
            remove
            {
                base.RemoveHandler(BeforeDialogEvent, value);
            }
        }

        ...

	}


  

--------------------------------------------------------------------------------------
Compensation  (undoing after an exception)
--------------------------------------------------------------------------------------
Compensation is the rollback operation of any successfully completed activity actions, 
because of an exception which is thrown somewhere in the workflow.

Activities inside a CompensatableSequenceActivity or a CompensatableTransactionScopeActivity 
activity are compensatable. Those two activities implement the ICompensatableActivity interface
which is required for a compensatable activity. 

An activity which implements the ICompensatableActivity interface can contain a single 
CompensationHandlerActivity as a child. A CompensationHandlerActivity is a CompositeActivity and can 
contain any number of child activities which perform the actual compensation actions. That CompensationHandlerActivity
and its children will be executed in case of a compensation because of an exception.

The CompensatableSequenceActivity and the CompensatableTransactionScopeActivity provide a "View Compensation Handler"
menu item, just like the "View Fault Handlers" menu item, which displays a view of their
CompensationHandlerActivity and where other activities can be added.

The CompensatableSequenceActivity is used when no transactions are involved to the execution.
The CompensatableTransactionScopeActivity is used with transactions and it requires the
presence of a persistence service registered with the runtime. 

--------------------------------------------------------------------------------------
Workflow configuration files 
--------------------------------------------------------------------------------------
A workflow host application can use a configuration file, app.config or web.config, in
order to configure the behavior of certain workflow runtime objects and other aspects
related to workflows.

Here is an example app.config

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>

        <configSections>
            <section name="MyWorkflowRuntime" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken 31bf3856ad364e35" />
        </configSections>
        
        <MyWorkflowRuntime>
            <CommonParameters>          
                <!-- parameters used by all workflow services such as connection strings -->
                <add name="ConnectionString" value="Initial Catalog=WorkflowStore; Data Source=localhost; Integrated Security=SSPI;" />
            </CommonParameters>
            
            <Services>         

                <!-- workflow services -->

            </Services>
        </MyWorkflowRuntime>

        <system.diagnostics>
            <switches>
                  <add name="System.Workflow.Runtime" value="All" />
                  <add name="System.Workflow.Runtime.Hosting" value="All" />
                  <add name="System.Workflow.Runtime.Tracking" value="Critical" />
                  <add name="System.Workflow.Activities" value="Warning" />
                  <add name="System.Workflow.Activities.Rules" value="Off" />

                  <add name="System.Workflow LogToFile" value="1" />
            </switches>
        </system.diagnostics>
        
    </configuration>


The <configSections> specifies configuration section and namespace declarations. The <section>
element associates a section element to another configuration element by using the name attribute.
In the above the 
    name="MyWorkflowRuntime" 
indicates that there is a separate <MyWorkflowRuntime> element elsewhere containing settings.
The MyWorkflowRuntime literal should be used by the host application when creates workflow runtime
instances.

    using(WorkflowRuntime workflowRuntime = new WorkflowRuntime("MyWorkflowRuntime"))
    {
        ...
    }
 
It is possible to have multiple workflow configuration sections inside of a configuration file.

The <CommonParameters> element contains <add> elements with name and value pairs for various settings,
such as connection strings, available to the services in the <Services> element.

The <Services> element contains services to be used with the workflow.

    <Services>
        <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="false"/>
    </Services>
    
It is possible to add a persistence service and configure its connection string at the same element.    
    
    <Services>
        <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService ..." connectionString="" />
    </Services>    
    
    
Logging can be valuable when debugging. WWF follows the configuration file format introduced
in .Net 2.0 to configure logging. 

    <system.diagnostics>
        <switches>
              <add name="System.Workflow.Runtime" value="All" />
              <add name="System.Workflow.Runtime.Hosting" value="All" />
              <add name="System.Workflow.Runtime.Tracking" value="Critical" />
              <add name="System.Workflow.Activities" value="Warning" />
              <add name="System.Workflow.Activities.Rules" value="Off" />

              <add name="System.Workflow LogToFile" value="1" />
        </switches>
    </system.diagnostics>

The <switches> element contains a number of <add> elements where each one is a name-value pair.
An <add> element defines a specific trace source and each trace source conveys trace
information from a different area of the workflow runtime. The possible values of the value
attribute are as following
    
    * All: logs all available messages for the source
    * Off: turns off tracing for the source
    * Critical: logs critical messages only      
    * Error: logs error messages only      
    * Warning: logs error and warning messages only         
    * Information: logs error, warning, critical and information messages    
    * Verbose: logs error, warning, critical, information and verbose messages    
 
The line
    <add name="System.Workflow LogToFile" value="1" />
directs logging information to a file using the name WorkflowTrace.log in the same directory
as the application. 

--------------------------------------------------------------------------------------
Workflow authoring modes 
--------------------------------------------------------------------------------------
WWF supports three authoring modes for implementing workflows
    * Code-only
    * Code-separation
    * No-code

Code-only. This is the default authoring mode. Workflows are defined using source code files
and designers. No XAML definition files are used. A code-only workflow must be compiled.
This is the only mode used so far by all examples. A code-only workflow may constructed totally
in code and without using designers at all.

Code-separation. Workflows are defined both in source code files and XAML markup files with a .xoml extension.
MS Visual Studio IDE provides special project and item wizards for creating workflows of this mode.
This mode mixes source code and markup. A code-separation workflow must be compiled.

No-code. Workflows are defined by just using XAML markup in .xoml files. No source code is involved.
Workflows are totally declarative. A no-code workflow can be compiled to an in-memory or to an in-disk
assembly if the markup code contains the x:Class attribute. Also a  no-code workflow can be loaded,
without any compilation, by just loading the .xoml definition file into the runtime engine.

see also: http://en.wikipedia.org/wiki/XAML

--------------------------------------------------------------------------------------
Using workflow authoring modes 
--------------------------------------------------------------------------------------
A Code-only mode and a Code-separation mode workflow are executed the same way by just using the type of
the workflow class when calling the WorkflowRuntime.CreateWorkflow() method.

    static void ExecuteWorkflow(Type WorkflowType)
    {
        using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
        { 
            AutoResetEvent waitHandle = new AutoResetEvent(false);
            workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); };
            workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
            {
                Console.WriteLine(e.Exception.Message);
                waitHandle.Set();
            };

            WorkflowInstance instance = workflowRuntime.CreateWorkflow(WorkflowType);
            instance.Start();

            waitHandle.WaitOne();
            Console.WriteLine("----------------------------------");
        }
    }
    
...

    ExecuteWorkflow(typeof(CodeOnly));                  // CodeOnly mode, the normal default mode
    ExecuteWorkflow(typeof(CodeSeparationWorkflow));    // Code-separation mode     
    
The same way is used with a compiled No-code mode workflow which may or may not contain source code
through the <x:Code> element. Compiling workflows is described next.

    static Type NoCode_Compiled()
    {
        string DataXML =
                @"<?xml version=""1.0"" encoding=""utf-8""?>                       " +
                "<SequentialWorkflowActivity                                        " +
                "xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/workflow\"    " +
                "xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"           " +
                "x:Class=\"Lessons.Workflows.NoCode_Compiled\" >                    " +
                "<CodeActivity ExecuteCode=\"act_ExecuteCode\" />                   " +
                "<x:Code>                                                           " +
                "   <![CDATA[                                                       " +
                "   private void act_ExecuteCode(object sender, EventArgs e)        " +
                "   {                                                               " +
                "      Console.WriteLine(\"Hi there, from: NoCode Compiled\");      " +
                "  }                                                                " +
                "   ]]>                                                             " +
                "</x:Code>                                                          " +
                "</SequentialWorkflowActivity>                                      "
                ;

        /* create and save a .xoml file */
        string[] Files = { @"..\..\NoCode_Compiled.xoml" };
        File.WriteAllText(Files[0], DataXML);


        /* create and setup a WorkflowCompiler */
        WorkflowCompiler compiler = new WorkflowCompiler();
        WorkflowCompilerParameters Params = new WorkflowCompilerParameters();
        Params.GenerateInMemory = true;


        /* compile the file(s) and check for any errors */
        WorkflowCompilerResults Results = compiler.Compile(Params, Files);

        if (Results.Errors.Count > 0)
            foreach (CompilerError ce in Results.Errors)
                Console.WriteLine(ce.ErrorText);

        /* load the NoCodeCompiledWorkflow class which is contained in the dynamically compiled assembly */
        return Results.CompiledAssembly.GetType("Lessons.Workflows.NoCode_Compiled");
    }        

...

    ExecuteWorkflow(NoCode_Compiled()); 

A No-code mode workflow may be executed without compilation though. This is the so-called
XAML activation. Since no compilation takes place with XAML activation, such a workflow .xoml file
can not contain inline source code or the x:Class="..." attribute. It can contain custom activities
though. 

The using of a custom activity in a .xoml file requires a proper namespace definition
of the namespace where the activity resides.
    xmlns:ns0="clr-namespace:Lessons.Workflows; Assembly=AuthoringModes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 

The XAML activation requires to load the .xoml file into an XmlReader object and pass
that object to the WorkflowRuntime.CreateWorkflow() method.

    static XmlReader NoCode_XAMLActivation()
    {
        string DataXML =
            @"<?xml version=""1.0"" encoding=""utf-8""?>                       " +
            "<SequentialWorkflowActivity                                        " + 
            "xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/workflow\"    " +
            "xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"           " +
            "xmlns:ns0=\"clr-namespace:Lessons.Workflows; Assembly=AuthoringModes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\" 	 " +
            //"x:Class=\"Lessons.Workflows.DynamicWorkflow\"     " +
             ">                                                                  " +
            "<ns0:TextActivity Text=\"NoCode XAML Activation\" />               " +
            "<DelayActivity TimeoutDuration=\"00:00:02\"  />                    " +
            "</SequentialWorkflowActivity>                                      "
            ;

        /* create and save a .xoml file */
        File.WriteAllText(NoCodeXAMLActivationFileName, DataXML);

        FileStream FS = File.OpenRead(NoCodeXAMLActivationFileName);
        return XmlReader.Create(FS);
    }
    
    
     /* executes a workflow passed as the content of an XmlReader object */
    static void ExecuteWorkflow(XmlReader Reader)
    {

        using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
        {       

            AutoResetEvent waitHandle = new AutoResetEvent(false);
            workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); };
            workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
            {
                Console.WriteLine(e.Exception.Message);
                waitHandle.Set();
            };

            WorkflowInstance instance = workflowRuntime.CreateWorkflow(Reader); 
            instance.Start();

            waitHandle.WaitOne();
            Console.WriteLine("----------------------------------");

        }
    }

...

    ExecuteWorkflow(NoCode_XAMLActivation());
    

--------------------------------------------------------------------------------------
Compiling workflows 
-------------------------------------------------------------------------------------- 
The WWF comes with a command-line workflow compiler, the wfc.exe. The workflow compiler
can be found at C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin. It is easily used
through the MS Visual Studio Command Prompt.

The WorkflowCompiler class can be used to compile workflows at run-time. 

    /* file names of .xoml files */
    string[] Files = { .... }; 

    /* create and setup a WorkflowCompiler */
    WorkflowCompiler compiler = new WorkflowCompiler();
    WorkflowCompilerParameters Params = new WorkflowCompilerParameters();
    Params.GenerateInMemory = true;

    /* compile the file(s) and check for any errors */
    WorkflowCompilerResults Results = compiler.Compile(Params, Files);

    if (Results.Errors.Count > 0)
        foreach (CompilerError ce in Results.Errors)
            Console.WriteLine(ce.ErrorText);

    /* load the workflow class which is contained in the dynamically compiled assembly */
    Type WorkflowType = Results.CompiledAssembly.GetType("NameOfTheWorkflowClass");
    
...

    WorkflowInstance instance = workflowRuntime.CreateWorkflow(WorkflowType);
    instance.Start();

For the compilation to succeed the .xoml has to contain the x:Class attribute.

When the WorkflowCompilerParameters.GenerateInMemory is true the generated assembly
is loaded automatically in the current application domain.

Here is a .xoml file which contains executable code of a No-code mode workflow.
The compilation of the following XAML code creates an assembly which contains the NoCode_Compiled class,
thanks to the x:Class="Lessons.Workflows.NoCode_Compiled" attribute contained in the XAML.

    <?xml version="1.0" encoding="utf-8"?>                       
     <SequentialWorkflowActivity                                     
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
     x:Class="Lessons.Workflows.NoCode_Compiled" >                                   
     <CodeActivity ExecuteCode="act_ExecuteCode" />                
     <x:Code>                                                        
        <![CDATA[                                                    
        private void act_ExecuteCode(object sender, EventArgs e)     
        {                                                            
           Console.WriteLine("Hi there, from: NoCode Compiled");   
       }                                                             
        ]]>                                                          
     </x:Code>                                                       
     </SequentialWorkflowActivity>                                   
           

And here is another .xoml file which defines a workflow containing a custom TextActivity activity
and a DelayActivity. 

    <?xml version="1.0" encoding="utf-8"?>                         
     <SequentialWorkflowActivity                                     
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"            
     xmlns:ns0="clr-namespace:Lessons.Workflows; Assembly=AuthoringModes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 	 
     x:Class="Lessons.Workflows.DynamicWorkflow"     
     >                                                                 
        <ns0:TextActivity Text="NoCode XAML Activation" />              
        <DelayActivity TimeoutDuration="00:00:02"  />                   
    </SequentialWorkflowActivity>   
    
Here is that custom TextActivity.

    public class TextActivity : Activity
    {
        public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(TextActivity));
        
        public TextActivity()
        {
        }

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext context)
        {
            Console.WriteLine("Hi there, from: {0}", Text);
            return ActivityExecutionStatus.Closed;
        }

        public string Text
        {
            get {  return ((string)(base.GetValue(TextProperty)));  }
            set {  base.SetValue(TextProperty, value);  }
        }
    }            
    
The using of a custom activity in a .xoml file requires a proper namespace definition
of the namespace where the activity resides.
    xmlns:ns0="clr-namespace:Lessons.Workflows; Assembly=AuthoringModes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 
                                            

--------------------------------------------------------------------------------------
Serializing workflows
--------------------------------------------------------------------------------------
Workflow serialization is done by using the WorkflowMarkupSerializer class. The XAML
produced by the WorkflowMarkupSerializer may be saved to a .xoml file or to any other
medium for later use.
           
    static void SerializeWorkflow()
    {
        WorkflowMarkupSerializer WS = new WorkflowMarkupSerializer();

        using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
        {
            using (StringWriter SW = new StringWriter())
            {
                using (XmlWriter XW = XmlWriter.Create(SW))
                {
                    Console.WriteLine("Serializing a Workflow");
                    Console.WriteLine("==================================");
                    WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(CodeSeparationWorkflow));
                    WS.Serialize(XW, instance.GetWorkflowDefinition());
                    Console.WriteLine(SW.ToString());
                    Console.WriteLine("----------------------------------");
                }
            }
        }
    }


--------------------------------------------------------------------------------------
Hosting the Workflow Designer 
--------------------------------------------------------------------------------------
The MSDN provides the excellent article "Windows Workflow Foundation: Everything About 
Re-Hosting the Workflow Designer" at http://msdn.microsoft.com/en-us/library/aa480213.aspx
by Vihang Dalal, which covers the hosting of the workflow designer in custom applications.
The sample project of the article can be used as a designer for sequential workflows and provides full access
to the internal Condition and Rules dialog boxes.

The sample can be downloaded from                                            
http://www.microsoft.com/downloads/details.aspx?FamilyID=3A331D20-44D4-4FB4-A833-F6EC9AEE1B82&displaylang=en

--------------------------------------------------------------------------------------
Editing RuleSet definitions with the RuleSetDialog class
--------------------------------------------------------------------------------------
The RuleConditionDialog class and the RuleSetDialog class are the dialog boxes used
by the MS Visual Studio IDE for editing Conditions and Rules. Those dialog boxes can
be used by a host application in order to provide condition and rule editing functionality.

The RuleSetDialog provides a constructor
    public RuleSetDialog(Type activityType, ITypeProvider typeProvider, RuleSet ruleSet);
for editing a RuleSet against a CLR class type.

    using (RuleSetDialog Dlg = new RuleSetDialog(typeof(Customer), null, ruleSet))
    {
        if (Dlg.ShowDialog() == DialogResult.OK)
            ruleSet = Dlg.RuleSet;
    }
    
Here are two methods for saving/loading rule sets to disk files.

    /* Saves RuleSet to FileName */
    static public void SaveToFile(RuleSet RuleSet, string FileName)
    {
        using (XmlWriter rulesWriter = XmlWriter.Create(FileName))
        {
            WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
            serializer.Serialize(rulesWriter, RuleSet);
        }
    }

    /* Loads and returns a RuleSet from FileName */
    static public RuleSet LoadFromFile(string FileName)
    {
        using (XmlTextReader rulesReader = new XmlTextReader(FileName))
        {
            WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
            return serializer.Deserialize(rulesReader) as RuleSet;
        }
    }
    
It is also possible to serialize a RuleSet to plain text for storing it anywhere
a string data can be saved.
    
    /* Returns the RuleSet converted to XML text */
    static public string ToText(RuleSet RuleSet)
    {
        StringBuilder SB = new StringBuilder();
        using (XmlWriter writer = XmlWriter.Create(SB))
        {
            WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
            serializer.Serialize(writer, RuleSet);
        }
        return SB.ToString();
    }


    /* Returns a RuleSet reading the rules in Text */
    static public RuleSet FromText(string Text)
    {
        RuleSet Result = null;
        if (!string.IsNullOrEmpty(Text))
        {
            using (XmlReader reader = XmlReader.Create(new StringReader(Text)))
            {
                WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
                Result = serializer.Deserialize(reader) as RuleSet;
            }
        }
        return Result;
    }
    
--------------------------------------------------------------------------------------
Using the WWF Rules Engine functionality
--------------------------------------------------------------------------------------    
The RuleSet class provides rules engine functionality. It provides two methods
    public bool Validate(RuleValidation validation);
    public void Execute(RuleExecution ruleExecution);
for validating and executing the RuleSet against any CLR object.

The classes involved in the process are the RuleValidation and RuleExecution class.

    /* executes RuleSet rules against Instance */
    static public void Execute(RuleSet RuleSet, object Instance)
    {
        if (RuleSet == null)
            throw new ArgumentNullException("RuleSet");

        if (Instance == null)
            throw new ArgumentNullException("Instance");

        RuleValidation ruleValidation = new RuleValidation(Instance.GetType(), null);
        RuleExecution ruleExecution = new RuleExecution(ruleValidation, Instance);
        RuleSet.Execute(ruleExecution);
    }
    
...

    Execute(LoadFromFile(FileName), customer);    
    
    
see also:   http://en.wikipedia.org/wiki/Rules_engine
                                     
